home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
DDJ0992.ARJ
/
DBISR.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-07-13
|
47KB
|
1,042 lines
;dbisr.asm
;Debugger interrupt service routines
;
;----------------------------------------------------------------------------
;Copyright 1991, 1992 ASMicro Co.
;7/6/91 Rick Knoblaugh
;-----------------------------------------------------------------------------
.386P
include dbequ.inc
include dbmac.inc
include dbstruc.inc
data segment para public 'data16' use16
extrn io_table:byte, IO_TAB_ENTRIES:abs,
extrn int1_active:byte, display_loc:word
extrn trace_count:word, wrk_vid_offset:word
extrn num_int_bp:byte, int_bpdat:byte, num_io_bp:byte
extrn io_instrucf:byte, io_inst_port:word, io_inst_info:byte
extrn tuser_cs:word, tuser_ip:word, trap_clear:byte
extrn num_table:byte
data ends
gdt_seg segment para public 'data16' use16
extrn sel_databs:byte
extrn sel_video:byte
extrn sel_data:byte
extrn sel_tss_alias:byte
gdt_seg ends
tss_seg segment para public 'data16' use16
tss_seg ends
zcode segment para public 'code16' use16
extrn int_9_isr:proc, int_1_isr:proc
zcode ends
isrcode segment para public 'icode16' use16
assume cs:isrcode, ds:nothing, es:nothing
;--------------------------------------------------------------
;PUBLICS |
;--------------------------------------------------------------
public int_1, int_0, int_2, int_3, int_4, int_5
public int_6, int_7, except_8, except_9, except_0ah
public except_0bh, except_0ch, except_0dh, except_0eh
public except_0fh, int_20h, int_21h, int_22h, int_23h
public int_24h, int_25h, int_26h, int_27h
public int_70h, int_71h, int_72h, int_73h
public int_74h, int_75h, int_76h, int_77h
;--------------------------------------------------------------
;Interrupt Service Routines |
;--------------------------------------------------------------
irp z, <0, 2, 3, 4, 5, 6, 7>
DOINT &z
endm
irp z, <8, 9, 0ah, 0bh, 0ch, 0dh, 0eh, 0fh>
DOEXCP &z
endm
irp z, <20h, 22h, 23h, 24h, 25h, 26h, 27h>
DOEXCPH &z
endm
irp z, <70h, 71h, 72h, 73h, 74h, 75h, 76h, 77h>
DOINT &z
endm
int_1 proc far
push bp
push 1 ;indicate it is int 1
mov bp, sp
pushad
mov ax, offset gdt_seg:sel_data
mov ds, ax
assume ds:data
mov eax, dr6 ;get debug status register
bt eax, deb_stat_bs
jc int_1_100 ;if single step trap
test al, 0fh ;look at bn status
jnz short int_1_200 ;if debug reg caused break
int_1_100: ;enter the debugger
cmp trace_count, 1 ;is debugger tracing?
jae short int_1_200 ;if so, go back into debugger
cmp io_instrucf, TRUE ;break caused by I/O ?
je short int_1_200 ;if so, go into debugger
xor eax, eax
mov dr6, eax ;clear debug status
popad
jmp pass_thru ;go to user's debugger
int_1_200:
cmp int1_active, TRUE ;should never be!!!!!!
jne short int_1_210
mov ax, offset gdt_seg:sel_video
mov es, ax
mov di, wrk_vid_offset
cld
mov al, 'B'
stosb
inc di
mov al, 'U'
stosb
inc di
mov al, 'G'
stosb
inc di
jmp $
int_1_210: ;<=======also JMPed to by gen_prot_isr
call adjust_ustack ;make return spot on user stack
;
;returns with [esi][edx] pointing to user stack area
;
;Create an IRET address on user stack so that IRET from int 1 will
;return to current cs:ip. Change return address on PL0 stack so that
;IRETD will return to debugger's int 1 handler.
;
;
mov ax, [bp].s_cs ;put on user cs
mov [esi][edx].user_cs, ax
mov eax, [bp].s_eip ;put on ip
mov [esi][edx].user_ip, ax
mov ax, offset int_1_isr
movzx eax, ax
mov [bp].s_eip, eax
mov ax, zcode
mov [bp].s_cs, ax
mov ax, offset gdt_seg:sel_data
mov ds, ax
assume ds:data
mov int1_active, TRUE ;make debugger active
assume ds:nothing
popad
add sp, 2 ;get rid of int number
pop bp
iretd
int_1 endp
;--------------------------------------------------------------
;int_21h - "int 9" ISR. If debugger is active, pass control |
; to debugger's int 9 routine. Otherwise, look for |
; the hot key. If not pressed, go to regular int 9 |
; ISR via the interrupt vector table. |
; |
; If hot key is pressed, set sel_data:int1_active |
; and fix stack so that debugger will be entered. |
; |
;--------------------------------------------------------------
int_21h proc far
push bp
push 9
mov bp, sp
pushad
mov ax, offset gdt_seg:sel_data
mov ds, ax
assume ds:data
cmp int1_active, TRUE ;is debugger active?
assume ds:nothing
jne short int_21h_100 ;if not, look for hot key
call adjust_ustack ;make return spot on user stack
;
;returns with [esi][edx] pointing to user stack area
;
;Create an IRET address on debugger's PL3 stack so that IRET from int 9 will
;return to current cs:ip. Change return address on PL0 stack so that
;IRETD will return to debugger's int 9 handler.
;
;
mov ax, [bp].s_cs ;put on debugger cs
mov [esi][edx].user_cs, ax
mov eax, [bp].s_eip ;put on ip
mov [esi][edx].user_ip, ax
mov ax, offset int_9_isr
movzx eax, ax
mov [bp].s_eip, eax
mov ax, zcode
mov [bp].s_cs, ax
jmp short int_21h_999
int_21h_100:
mov ax, offset gdt_seg:sel_databs
mov ds, ax
mov bx, KBD_FLAG
mov al, [bx + 400h] ;bios data area
and al, LR_SHIFT
cmp al, LR_SHIFT
je short int_21h_200
popad
jmp pass_thru ;if not hot key go do
;regular int 9
int_21h_200:
mov ax, offset gdt_seg:sel_data
mov ds, ax
assume ds:data
mov int1_active, TRUE ;debugger active
assume ds:nothing
call adjust_ustack ;make return spot on user stack
;
;returns with [esi][edx] pointing to user stack area
;
;Create an IRET address on user stack so that IRET from int 1 will
;return to current cs:ip.
mov ax, [bp].s_cs ;put on user cs
mov [esi][edx].user_cs, ax
mov eax, [bp].s_eip ;put on ip
mov [esi][edx].user_ip, ax
;Change return address on PL0 stack so that IRETD will return to old
;int 9 handler.
;
mov bx, (9 * 4) ;get int vector
movzx eax, [bx].d_offset ;offset portion
mov [bp].s_eip, eax
mov ax, [bx].d_seg ;segment portion
mov [bp].s_cs, ax
call adjust_ustack ;make return spot on user stack
;Create an IRET address on user stack so that IRET from int 9 will
;return to debugger's int 1.
mov ax, zcode
mov [esi][edx].user_cs, ax
mov ax, offset int_1_isr
mov [esi][edx].user_ip, ax
int_21h_999:
popad
add sp, 2 ;get rid of int number
pop bp
iretd
int_21h endp
;--------------------------------------------------------------
;do_bit_map - For the number of ports specified, clear/set |
; corresponding I/O permission map bits. |
; |
; Enter: Ah = 0 clear, ah = 1 set |
; dx = starting port |
; cx = number of ports |
; All registers saved. |
;--------------------------------------------------------------
do_bit_map proc near
push ax
push bx
push cx
push dx
mov bx, offset gdt_seg:sel_tss_alias
mov ds, bx
assume ds:tss_seg
mov bx, t_iomap
push cx
mov cx, dx ;port
and cl, 7 ;get non byte boundary
mov al, 1 ;first bit position
shl al, cl ;get out corresponding bit
shr dx, 3 ;start_port/8
pop cx
add bx, dx ;starting offset in map
do_bit100:
or ah, ah
jnz short do_bit200
mov dl, al
not dl
and byte ptr [bx], dl ;turn off permission bit
jmp short do_bit250
do_bit200:
or byte ptr [bx], al ;turn on permission bit
do_bit250:
rcl al, 1 ;next bit position
jnc short do_bit300
inc bx
rcl al, 1
do_bit300:
loop do_bit100
pop dx
pop cx
pop bx
pop ax
ret
do_bit_map endp
;--------------------------------------------------------------
;except_handler - Process as follows: |
; |
; Int 0dh - Go look for software int or |
; I/O instruction. |
; Any other |
; exception - Go display exception number |
; and halt. |
;--------------------------------------------------------------
except_handler proc near
mov bp, sp
cmp [bp].e_pushed_int , GEN_PROT_EXCEP
je gen_prot_isr
mov ax, [bp].e_pushed_int ;int in ax
;fall through to fatal_error
except_handler endp
fatal_error:
call display_it
jmp $
;--------------------------------------------------------------
;display_it - Display hex number on screen at next display |
; offset of video page 0. This is used for |
; debugging. |
; |
; Enter: number in AX |
; |
; Exit: sel_data:display_loc will contain |
; location on screen for next display. |
; |
; All registers saved |
;--------------------------------------------------------------
display_it proc near
pusha
push ds
push es
mov dx, offset gdt_seg:sel_data
mov ds, dx ;get our data segment
assume ds:data
mov dx, offset gdt_seg:sel_video
mov es, dx ;and video segment
mov di, display_loc
call put_hex_word
add di, 2 ;past space and attribute
cmp di, PAGE_SIZE - 100h ;at bottom of screen?
jb short display_i100
xor di, di ;if so, back to start of page
display_i100:
mov display_loc, di
pop es
pop ds
popa
ret
display_it endp
put_hex_word:
mov dl, al ;save LSB
mov al, ah ;want to print MSB first
call put_hex_byte
mov al, dl
put_hex_byte:
mov ah, al
put_hex_100:
shr al, 4 ;get high portion
call put_nibble
mov al, ah
and al, 0fh
put_nibble:
mov bx, offset num_table
xlat
stosb
inc di ;past attribute
ret
;--------------------------------------------------------------
;pass_thru - This procedure is JMPed to by any interrupt |
; handler which wishes to pass control to the |
; original ISR per the interrupt vector table. |
; |
; Also, it checks to see if there are any break |
; points set on the int. If there are, the int |
; being passed through is checked to see if it |
; matches the condition for the break point. If |
; the condition for the break point is met, DR0 |
; is used to cause a break at the ISR. |
; |
; Enter: |
; See stack_area struc for stack layout |
; Any error code has been removed from stack.|
; EIP on stack has been adjusted if |
; necessary. |
;--------------------------------------------------------------
pass_thru proc near
mov bp, sp
pushad
call adjust_ustack ;adjust user stack
;
;returns with [esi][edx] pointing to user stack area
;
mov cx, [bp].s_cs ;put on user cs
mov [esi][edx].user_cs, cx
mov ecx, [bp].s_eip ;put on ip
mov [esi][edx].user_ip, cx
movzx ebx, [bp].s_pushed_int ;get int number
movzx ecx, [ebx * 4].d_offset ;offset portion
mov [bp].s_eip, ecx
mov cx, [ebx * 4].d_seg ;segment portion
mov [bp].s_cs, cx
pass_thru200:
mov cx, offset gdt_seg:sel_data
mov fs, cx
assume fs:data
push fs
cmp fs:trap_clear, TRUE ;tracing through an int?
jne short pass_thru500
mov fs:trap_clear, FALSE ;reset it
mov fs:int1_active, TRUE ;debugger active
;
;If tracing through a software INT instruction, don't want the INT to
;be treated as one instruction (trap flag is cleared upon entering
;interrupts). In order to single step starting with the first instruction
;of the ISR, move address of the first instruction onto the user's stack
;and make user cs:ip on PL0 stack point to debugger int 1.
;
sub edx, 6 ;flags, cs, ip
mov [bp].s_esp, edx ;adjust it
mov ecx, [bp].s_eflags ;put on flags
mov [esi][edx].user_flags, cx
mov cx, [bp].s_cs ;put &ISR onto user's stack
mov [esi][edx].user_cs, cx
mov ecx, [bp].s_eip
mov [esi][edx].user_ip, cx
mov cx, ZCODE
mov [bp].s_cs, cx
mov cx, offset int_1_isr
movzx ecx, cx
mov [bp].s_eip, ecx
pass_thru500:
pop ds ;get data seg (was fs)
assume ds:data
cmp int1_active, TRUE ;is debugger active?
je short pass_thru999 ;if so, don't even think
;of breaking
movzx cx, num_int_bp ;number of defined int breaks
jcxz pass_thru999 ;if no int type break points
mov si, offset int_bpdat
pass_thru700:
cmp [si].int_stat, ACTIVE ;is break on int enabled?
jne short pass_thru800
dec cx
cmp [si].int_num, bl ;is this the int specified?
jne short pass_thru800
cmp [si].int_reg, NO_CONDITION ;no conditions?
je short pass_thru750 ;if none go ahead and set break
mov dx, [si].int_val ;get data for comparison
cmp [si].int_reg, INT_AL_COMP ;condition compare on al?
jne short pass_thru730
cmp al, dl ;condition met?
je pass_thru750 ;if so, go ahead and set break
jmp short pass_thru800 ;if != look for more conditions
pass_thru730:
cmp [si].int_reg, INT_AH_COMP ;condition compare on ah?
jne short pass_thru740
cmp ah, dl ;condition met
je short pass_thru750 ;if so, go ahead and set break
jmp short pass_thru800 ;if != look for more conditions
pass_thru740: ;condition compare on ax
cmp ax, dx
jne short pass_thru800 ;if != look for more conditions
pass_thru750:
mov ebx, [bp].s_eip ;get offset and
movzx edx, [bp].s_cs ;segment of ISR
shl edx, 4 ;convert to linear
add edx, ebx
mov ch, 1 ;set debug register
mov al, DEB_DAT_LEN1 ;exec breaks use 1 byte length
mov ah, DEB_TYPE_EXEC
sub cl, cl ;debug reg zero
call do_debug_reg
jmp short pass_thru999
pass_thru800:
add si, size info_int ;advance to next int break
or cl, cl ;all int breaks checked?
jnz short pass_thru700 ;if not, check the next one
pass_thru999:
popad
add sp, 2 ;get rid of int number
pop bp
iretd
pass_thru endp
;--------------------------------------------------------------
;adjust_ustack - Make room for flags and a far address on the |
; user stack. Place flags from PL0 stack |
; on user stack. The caller of this routine |
; will then place the far address on the user |
; stack. |
; |
; Enter: |
; bp=base of PL0 stack |
; Exit: |
; esi=linear address of user stack segment |
; edx=adjusted user sp |
; ds=absolute zero selector |
; |
; No registers saved (AX not used) |
;--------------------------------------------------------------
adjust_ustack proc near
mov cx, offset gdt_seg:sel_databs
mov ds, cx
movzx esi, [bp].s_ss ;user stack
shl esi, 4 ;make linear
mov edx, [bp].s_esp ;user stack pointer
sub edx, 6 ;flags, cs, ip
mov [bp].s_esp, edx ;adjust it
mov ecx, [bp].s_eflags ;put on flags
mov [esi][edx].user_flags, cx
;
;Change flags on stack so that original ISR will be entered with
;interrupts cleared and trap flag cleared to be consistent with their
;state upon entering an ISR (the normal way).
;
;
and ecx, not ( (mask resumef) OR (mask inter) OR (mask trapf))
mov [bp].s_eflags, ecx ;put back flags
ret
adjust_ustack endp
;--------------------------------------------------------------
;gen_prot_isr - JMP here if int 0dh. |
; |
; Look for software int. If a software int |
; caused the exception then: |
; |
; If debugger is active, look for user software |
; interrupts issued by PL3 layer of debugger. |
; |
; If int 15h function 89h deny. |
; |
; If int 15h function 87h, emulate it. |
; |
; If none of these, simply route the interrupt |
; per the real mode interrupt vector table. |
; |
; If exception was not caused by a software |
; int and there are break points defined on |
; I/O accesses, look for I/O instruction. If |
; it is an I/O instruction, temporarily clear |
; the corresponding TSS I/O permission bit map |
; bit and set trap flag to single step through |
; the instruction. |
; |
; If other than software int or I/O, display |
; cs:ip, 0dh and then halt. |
; |
;--------------------------------------------------------------
gen_prot_isr proc near
pushad
;
;Note: Don't use DX or AX below as DX may contain an I/O port address and
; in the case of a software interrupt, AH will have a function code.
; Also, don't use SI or CX as they are inputs for the extended memory
; block move function
;
mov bx, offset gdt_seg:sel_databs
mov ds, bx
movzx ebx, [bp].e_cs ;get cs of user instruction
shl ebx, 4 ;make linear
add ebx, [bp].e_eip ;add ip
mov bx, [ebx] ;get bytes at cs:ip
mov di, offset gdt_seg:sel_data
mov ds, di ;debugger's data
cmp bl, INT_OPCODE
je short gen_prot020
cmp bl, INT3_OPCODE
jne gen_prot150 ;go look for I/O instruction
mov bh, 3 ;interrupt 3
gen_prot020:
cmp trace_count, 0 ;is debugger tracing?
je short gen_prot040 ;if not, skip test below
;See if this software interrupt is the instruction through which the user
;is tracing. If it is, set flag.
mov di, [bp].e_cs
cmp di, tuser_cs
jne short gen_prot040
mov edi, [bp].e_eip
cmp di, tuser_ip
jne short gen_prot040
;
;Clear trap bit so that it will not be set on user stack.
;Note: If user is doing a "trace n" where n is a number of instructions
;exceeding the number of instructions in the ISR, instructions executing upon
;return from the ISR will still be trapped through as the int 1 code will
;again set the trap flag.
;
btr [bp].e_eflags, trapf
mov trap_clear, TRUE
gen_prot040:
inc [bp].e_eip ;get past the 0cdh (or 0cch)
cmp bh, 3 ;int 3?
je short gen_prot060 ;if so, only 1 byte
gen_prot050:
inc [bp].e_eip
gen_prot060:
;
;See if the debugger is active and if this software interrupt is one of the
;ones used by the PL3 portion of the debugger to get PL0 services.
;
cmp int1_active, TRUE ;is debugger active?
jne short gen_prot085
;
;Note: In the event that an interrupt occuring while debugger is active
; (e.g. timer) actually uses these user software interrupts,
; code to verify caller would need to be added here.
;
cmp bh, 60h ;do debug registers?
jne short gen_prot080
popad
call do_debug_reg
jmp gen_prot299
gen_prot080:
cmp bh, 61h ;do I/O bit map?
jne short gen_prot085
popad
;
;Unlike the accessing of debug registers, PL3 code could actually manipulate
;the TSS I/O bit map directly. However, this interface keeps this in
;one location.
;
call do_bit_map
jmp gen_prot299
gen_prot085:
cmp bh, 15h ;int 15?
jne short gen_prot100
cmp ah, 89h ;request for protected mode?
jne short gen_prot090
;if so, can't allow
bts [bp].e_eflags, carry ;set carry
popad
jmp gen_prot299 ;and return
gen_prot090:
cmp ah, 87h ;request for extended move?
jne short gen_prot100
call emulate_blk_mov ;if so, we must do it
popad
mov ah, 0 ;default to success
jnz gen_prot299 ;exit if success
mov ah, 3 ;indicate a20 gate failed
jmp gen_prot299 ;and return
gen_prot100:
;
;Adjust stack so that error code goes away and int number retrieved from
;instruction goes in spot on stack where pushed int number is (for stacks
;with no error code). Stack will be the way pass_thru routine likes it.
;
mov ax, bx
mov bx, [bp].e_pushed_bp
shl ebx, 16 ;get into high word
mov bl, ah ;interrupt number
mov [bp].e_errcode, ebx
cmp bl, 1 ;software int 1?
jne short gen_prot140
;Below, check to see if we are already in the debugger. This is only to
;handle the unlikely case where there is an actual INT 1 instruction inside
;of an interrupt handler. If there is and the debugger is active, the
;instruction will be ignored.
popad
cmp int1_active, TRUE ;already in debugger?
jne short gen_prot130 ;if not, go enter int 1
;else ignore it by returning
add sp, 2 ;get rid of int number
pop bp
iretd
gen_prot130:
add sp, 4 ;error code gone
mov bp, sp
pushad
jmp int_1_210 ;go enter int 1
gen_prot140:
popad
add sp, 4 ;error code gone
jmp pass_thru ;route the int via vectors
gen_prot150:
cmp num_io_bp, 0 ;any I/O break points defined?
je short gen_prot400 ;if not, don't look for I/O
xor ah, ah ;use as string flag
cmp bl, REP_PREFIX ;rep ?
jne short gen_prot190
mov ah, STRING ;only string type use rep
mov bl, bh ;get 2nd byte
gen_prot190:
;
; If repeat prefix was found, ah now has a flag indicating only
; string type I/O instructions should be expected and bl now contains
; the byte of object code past the repeat prefix.
;
; Note: To be complete, this code should also look for the
; operand-size prefix and segment overrides.
;
;
mov si, offset io_table
mov cx, IO_TAB_ENTRIES
gen_prot200:
or ah, ah ;strings only?
jz short gen_prot225 ;if not, don't test
test [si].io_info, ah ;if table entry is not a string
jz short gen_prot300 ;type I/O, go try next one
gen_prot225:
cmp bl, [si].io_opcode
jne short gen_prot300
mov io_instrucf, TRUE ;instruction found
mov cl, [si].io_info ;get info about instruction
mov io_inst_info, cl ;save it
test cl, CONSTANT ;port number in instruction?
jz short gen_prot250 ;if not, we have it
movzx dx, bh ;get port
gen_prot250:
mov io_inst_port, dx ;save port
mov cx, 1 ;number of bits
sub ah, ah ;indicate clear
call do_bit_map
gen_prot260:
bts [bp].e_eflags, trapf ;single step i/o
popad
gen_prot299:
add sp, 2 ;int number pushed
pop bp
add sp, 4 ;error code
iretd
gen_prot300:
add si, size io_struc ;advance to next table entry
loop gen_prot200
gen_prot400:
;
;Also need to add code here to check for a few other exceptions (e.g.
;the HLT instruction).
;
mov ax, [bp].e_cs ;get cs of user instruction
call display_it
mov eax, [bp].e_eip ;add ip
call display_it
popad
mov ax, [bp].e_pushed_int
jmp fatal_error
gen_prot_isr endp
;--------------------------------------------------------------
;emulate_blk_mov - Called from gen_prot_isr when an int 15h |
; function 87h (extended memory block move) |
; is detected. Perform the function and |
; return. |
; |
; Enter: |
; es on PL0 stack and SI form a |
; pointer to user's GDT |
; |
; cx=number of words to move |
; |
; Exit: Indicate success by affecting flags |
; image on PL0 stack. |
; |
; Zero flag set if error (for now |
; the only error checked for is |
; an A20 failure - other error |
; checks should be added). |
; |
;--------------------------------------------------------------
emulate_blk_mov proc near
mov ax, offset gdt_seg:sel_databs ;absolute zero base
mov ds, ax
mov es, ax
;First, determine if a20 is already set
mov ebx, 100000h ;1 meg
xor dl, dl ;use dl for a20 flag
push dword ptr [ebx] ;get contents at "1 meg"
mov eax, 0ffffffffh
mov dword ptr [ebx], eax ;move test value there
xor edi, edi
cmp dword ptr [edi], eax ;did it wrap to zero
pop dword ptr [ebx] ;restore value
je short emulate_b025 ;if so, a20 not set
mov dl, 1 ;indicate a20 already set
jmp short emulate_b100
emulate_b025:
mov al, 1 ;set a20 function
call do_a20
jnz short emulate_b100
emulate_b050:
bts [bp].e_eflags, carry ;indicate error
btr [bp].e_eflags, zero
ret
emulate_b100:
movzx ebx, [bp].e_es ;get user's es
shl ebx, 4 ;make linear
movzx esi, si
mov eax, 00ffffffh ;24 bit address only
;get destination address
mov edi, dword ptr [ebx][esi].ex_mdest.seg_base_low
and edi, eax ;24 bit address only
;get source address
mov esi, dword ptr [ebx][esi].ex_msource.seg_base_low
and esi, eax ;24 bit address only
cld
movzx ecx, cx ;word count
shr cx, 1 ;convert to dword count
jnc short emulate_b500 ;if evenly div by 4
db 67h ;force 32 bit addressing
movsw ;move odd one
jcxz emulate_b600 ;if only 1 word was requested
emulate_b500:
db 67h ;force 32 bit addressing
rep movsd ;move dwords
emulate_b600:
test dl, 1 ;a20 already set when entered?
jnz short emulate_b999
sub al, al ;clear a20 function
call do_a20
jz short emulate_b050 ;if error
emulate_b999:
btr [bp].e_eflags, carry ;indicate success
bts [bp].e_eflags, zero
ret
emulate_blk_mov endp
;--------------------------------------------------------------
;do_a20 - Turn A20 on or off. |
; |
; Enter: |
; al=1 turn it on. |
; al=0 turn it off. |
; |
; Exit: Zero set if error |
; |
; No registers saved. |
;--------------------------------------------------------------
do_a20 proc near
mov ah,0dfh ;a20 on
or al,al
jnz short do_a20_100
mov ah,0ddh ;a20 off
do_a20_100:
call key_wait
jz short do_a20_999
mov al,0d1h
out 64h,al
call key_wait
mov al,ah
out 60h,al
call key_wait
jz short do_a20_999
mov al,0ffh
out 64h,al
call key_wait
do_a20_999:
ret
do_a20 endp
key_wait proc near
push cx
xor cx,cx ;max time out
key_w100:
dec cx
jz short key_w999
in al,64h
and al,2
jnz short key_w100 ;loop if keyboard controller not ready
key_w999: or cx,cx ;return with zero set if error
pop cx
ret
key_wait endp
;----------------------------------------------------------------------
; do_debug_reg - enable/disable debug register for break point. |
; |
; Enter: ch = 0 if clearing break point |
; ch = 1 if setting break point |
; ch = 2 if setting up break point type and |
; address, but not enabling yet |
; |
; ch = 3 get bn portion of debug status register |
; into ax (then clear status register) |
; |
; if clearing and eax !=0, eax holds other |
; bits to be cleared (used for also clearing |
; ge or le bits) |
; |
; cl = debug register number (0-3) |
; |
; if setting also have: |
; |
; al = length (0=1 byte, 1=2 bytes, 3=4 bytes) |
; ah = type (0=execution, 1=write, 3=read/write) |
; edx = linear address for break |
; |
; also, if al='*' simply reactivate the break |
; point keeping the existing type and address. |
; |
; Exit: if disabling, specified debug register break |
; point is disabled. |
; |
; if enabling, specified debug register is loaded |
; and break point is enabled. |
; |
; if getting debug status register, bn portion of |
; DR6 is returned in AX. |
; |
; Save ebx. |
;----------------------------------------------------------------------
do_debug_reg proc near
cmp ch, 3 ;requesting status?
jne short do_deb050 ;if not
mov eax, dr6 ;debug status register
xor edx, edx
mov dr6, edx ;clear status
and ax, 0fh ;isolate bn status
ret ;and return
do_deb050:
push ebx
mov ebx, dr7 ;get debug control reg
cmp ch, 1 ;determine function
jb short do_deb850 ;if clear function go do it
ja short do_deb100 ;setup, but not enable
cmp al, '*' ;simply reset?
je short do_deb850
do_deb100:
push cx ;save function/reg #
push edx ;save linear address
mov edx, 0fh ;4 on bits
shl cl, 2 ;reg # * bits associated
add cl, 16 ;upper portion of 32 bit reg
shl edx, cl
not edx ;associated bits off
and ebx, edx ;in the dr7 value
shl al, 2 ;length bits to len position
or al, ah ;put in the type
mov dl, ah ;save type
sub ah, ah
shl eax, cl ;move len/rw to position
or ebx, eax
or dl, dl ;execution type?
jz short do_deb500 ;if so, don't need ge
bts bx, ge_bit
do_deb500:
pop edx ;restore linear address
pop cx ;and debug register #
cmp cl, 1
je short do_deb600
ja short do_deb700
mov dr0, edx
jmp short do_deb800
do_deb600:
mov dr1, edx
jmp short do_deb800
do_deb700:
cmp cl, 3
je short do_deb750
mov dr2, edx
jmp short do_deb800
do_deb750:
mov dr3, edx
do_deb800:
cmp ch, 2 ;setup, but not enable?
je short do_deb900 ;if so, skip enable
do_deb850:
shl cl, 1 ;get to global enable for #
inc cl
movzx dx, cl ;bit number to turn on
bts bx, dx ;set on in dr7 value
or ch, ch ;set function?
jnz short do_deb900
btr bx, dx ;if not, disable break
or ax, ax ;clear ge or le?
jz short do_deb900 ;if not continue
btr bx, ax ;if so, clear ge or le bit
do_deb900:
mov dr7, ebx ;put adjusted value back
pop ebx
do_deb999:
ret
do_debug_reg endp
isrcode ends
end